Flutter AndroidShellHolder
介绍
AndroidShellHolder 是 Flutter 在 Android 端的核心资源管理类,Flutter 的 4 条线程,就是在该类中创建的。Flutter 中的核心组件 Shell 也是在该类中创建的。由此可见,AndroidShellHolder 是一个非常重要的初始化入口。
构造
AndroidShellHolder 的构造方法是重中之重。这里把该方法拆解来看。
线程创建
首先会创建 Flutter 所需要的线程:
static size_t thread_host_count = 1;
auto thread_label = std::to_string(thread_host_count++);
thread_host_ = std::make_shared<ThreadHost>();
if (is_background_view) {
*thread_host_ = {thread_label, ThreadHost::Type::UI};
} else {
*thread_host_ = {thread_label, ThreadHost::Type::UI |
ThreadHost::Type::RASTER |
ThreadHost::Type::IO};
}
其中:
- 有两种工作模式,通过 is_background_view 辩别
- 创建 4 条线程
具体线程创建位于 ThreadHost:
ThreadHost::ThreadHost(std::string name_prefix_arg, uint64_t mask)
: name_prefix(name_prefix_arg) {
if (mask & ThreadHost::Type::Platform) {
platform_thread = std::make_unique<fml::Thread>(name_prefix + ".platform");
}
if (mask & ThreadHost::Type::UI) {
ui_thread = std::make_unique<fml::Thread>(name_prefix + ".ui");
}
if (mask & ThreadHost::Type::RASTER) {
raster_thread = std::make_unique<fml::Thread>(name_prefix + ".raster");
}
if (mask & ThreadHost::Type::IO) {
io_thread = std::make_unique<fml::Thread>(name_prefix + ".io");
}
if (mask & ThreadHost::Type::Profiler) {
profiler_thread = std::make_unique<fml::Thread>(name_prefix + ".profiler");
}
}
需要注意的是,在上面创建的新线程里面,不包含 platform 线程。
还有一点需要注意的是,所创建的线程是 fml::Thread,其内部同时也在线程上生成了消息队列(TaskRunner)
TaskRunner 初始化
接下来需要对各个线程的 TaskRunner 进行初始化:
// 使用当前线程(主线程)作为 Platform Thread
// 因此首先要在主线程上初始化消息队列
fml::MessageLoop::EnsureInitializedForCurrentThread();
// 其它三个 Runner,待会儿从新创建的线程中拿
fml::RefPtr<fml::TaskRunner> raster_runner;
fml::RefPtr<fml::TaskRunner> ui_runner;
fml::RefPtr<fml::TaskRunner> io_runner;
// Platform Runner 直接从当前线程(主线程)拿
fml::RefPtr<fml::TaskRunner> platform_runner =
fml::MessageLoop::GetCurrent().GetTaskRunner();
// 其它三个 Runner,从新创建的线程中拿
if (is_background_view) {
auto single_task_runner = thread_host_->ui_thread->GetTaskRunner();
raster_runner = single_task_runner;
ui_runner = single_task_runner;
io_runner = single_task_runner;
} else {
// 通常是这一种
raster_runner = thread_host_->raster_thread->GetTaskRunner();
ui_runner = thread_host_->ui_thread->GetTaskRunner();
io_runner = thread_host_->io_thread->GetTaskRunner();
}
// 把几个 runner 都塞进 TaskRunners 保管
flutter::TaskRunners task_runners(thread_label, // label
platform_runner, // platform
raster_runner, // raster
ui_runner, // ui
io_runner // io
);
// raster 线程队列的第一个任务是调整该线程优先级
// 通过 PostTask 向 TaskRunner 抛任务
// 线程优先级,-8 表示最重要的显示线程,raster 优先级略低于显示
// 数字越小优先级越高
task_runners.GetRasterTaskRunner()->PostTask([]() {
if (::setpriority(PRIO_PROCESS, gettid(), -5) != 0) {
// 有的系统不让设置优先级太高,再调低点
if (::setpriority(PRIO_PROCESS, gettid(), -2) != 0) {
FML_LOG(ERROR) << "Failed to set raster task runner priority";
}
}
});
// UI Thread 优先级是 -1
task_runners.GetUITaskRunner()->PostTask([]() {
if (::setpriority(PRIO_PROCESS, gettid(), -1) != 0) {
FML_LOG(ERROR) << "Failed to set UI task runner priority";
}
});
// IO Thread 优先级是 +1
task_runners.GetIOTaskRunner()->PostTask([]() {
if (::setpriority(PRIO_PROCESS, gettid(), 1) != 0) {
FML_LOG(ERROR) << "Failed to set IO task runner priority";
}
});
其中:
- 可以看到,Platform Thread 直接使用了当前线程(主线程)
- 因此需要在主线程初始化线程队列 fml::MessageLoop::EnsureInitializedForCurrentThread();
- 这里的 task_runners 属性待会儿会传给 Shell 中存起来
Shell 创建
Shell 是 Flutter Engine 中非常核心的一个枢纽,通过它能够调度 Flutter Engine 中各个核心组件。
线程准备完毕后,接下来就该 Shell 创建:
shell_ =
Shell::Create(GetDefaultPlatformData(), // window data
task_runners, // task runners
settings_, // settings
on_create_platform_view, // platform view create callback
on_create_rasterizer // rasterizer create callback
);
if (shell_) {
shell_->GetDartVM()->GetConcurrentMessageLoop()->PostTaskToAllWorkers([]() {
// DartVM 里面有一个线程池,将优先级调整成 +1
if (::setpriority(PRIO_PROCESS, gettid(), 1) != 0) {
FML_LOG(ERROR) << "Failed to set Workers task runner priority";
}
});
// 初始化图片解码器
shell_->RegisterImageDecoder(
[runner = task_runners.GetIOTaskRunner()](sk_sp<SkData> buffer) {
return AndroidImageGenerator::MakeFromData(buffer, runner);
},
-1);
}
其中:
- 在 Shell 的创建过程中,还有两个异步惠回调:on_create_platform_view、on_create_rasterizer,也都是非常核心的两个初始化过程,由 Shell 进行调度
下面分别给出两个回调的实现。
on_create_platform_view
fml::WeakPtr<PlatformViewAndroid> weak_platform_view;
Shell::CreateCallback<PlatformView> on_create_platform_view =
[is_background_view, &jni_facade, &weak_platform_view](Shell& shell) {
std::unique_ptr<PlatformViewAndroid> platform_view_android;
platform_view_android = std::make_unique<PlatformViewAndroid>(
shell, // delegate
shell.GetTaskRunners(), // task runners
jni_facade, // JNI interop
shell.GetSettings()
.enable_software_rendering, // use software rendering
!is_background_view // create onscreen surface
);
weak_platform_view = platform_view_android->GetWeakPtr();
auto display = Display(jni_facade->GetDisplayRefreshRate());
shell.OnDisplayUpdates(DisplayUpdateType::kStartup, {display});
return platform_view_android;
};
可以看到创建了一个 PlatformViewAndroid 对象实例。
on_create_rasterizer
Shell::CreateCallback<Rasterizer> on_create_rasterizer = [](Shell& shell) {
return std::make_unique<Rasterizer>(shell);
};
收尾
在构造方法的最后,AndroidShellHolder 把 PlatformViewAndroid 给存下来了:
platform_view_ = weak_platform_view;
FML_DCHECK(platform_view_);
is_valid_ = shell_ != nullptr;
}
调用
AndroidShellHolder 是在哪里进行创建的呢?
- attachJNI(platform_view_android_jni_impl.cc),attachJNI 就是 FlutterJNI 的 nativeAttach
- FlutterJNI.performNativeAttach
- FlutterJNI.attachToNative
- FlutterEngine.attachToJni
- FlutterEngine java 类构造函数
- FlutterEngine.attachToJni
- FlutterJNI.attachToNative
- FlutterJNI.performNativeAttach